/*
* ECARX Technology Limited is the owner of the copyright and the trade secret of this software.
* Without permission, no one has the right to obtain, disclose or use this software in any way.
*/

package ecarx.xsf.notificationcenter.manager;

import android.text.TextUtils;
import android.util.Log;


import ecarx.xsf.notificationcenter.common.Constants;
import ecarx.xsf.notificationcenter.model.BuildCompetition;
import ecarx.xsf.notificationcenter.model.Competition;
import ecarx.xsf.notificationcenter.notification.ICardNotificationListener;

import ecarx.xsf.notificationcenter.scenecard.ISceneCardInfo;
import ecarx.xsf.notificationcenter.scenecard.ISceneCardInfoV2;
import ecarx.xsf.notificationcenter.scenecard.ISceneCardListener;
import ecarx.xsf.notificationcenter.scenecard.ISceneCardListenerV2;
import ecarx.xsf.notificationcenter.sdk.IStatusBarNotification;
import ecarx.xsf.notificationcenter.task.Callback;
import ecarx.xsf.notificationcenter.task.TPE;

import java.util.List;


/**
 * FileName: CompetitionStrategyDataManager.java <br>
 * Description : 消息队列竞合策略 <br>
 * Create Time: 2020/03/17 11:32 <br>
 * Update Time: 2021/8/4 11:32 <br>
 *
 * @since 1.0.0
 */
public class CompetitionStrategyDataManager {

    private static final String TAG = "CompetitionStrategy";

    private final QueueManager mQueueManager;
    private List<ICardNotificationListener> mCallbackList;
    private List<ISceneCardListener> mSceneCallback;
    private List<ISceneCardListenerV2> mSceneCallbackV2;
    private Competition mPastCompetition;
    private ISceneCardInfoV2 lastSendSceneInfo;

    private static class CompetitionStrategyDataManagerInstance {
        static final CompetitionStrategyDataManager INSTANCE = new CompetitionStrategyDataManager();
    }

    public static CompetitionStrategyDataManager get() {
        return CompetitionStrategyDataManagerInstance.INSTANCE;
    }

    private CompetitionStrategyDataManager() {
        mQueueManager = new QueueManager();
        mQueueManager.setOnAddCompleteListener(new QueueManager.IAddQueueCompleteListener() {
            @Override
            public void onComplete() {
                Log.i(TAG, "queue add completed, will send out ");
                onNotificationSend(mQueueManager.getCompetition());
            }

            @Override
            public void onSceneCardComplete() {
                Log.i(TAG, "card queue add completed, will send out ");
            }
        });
    }

    private boolean doSend(ISceneCardInfoV2 iSceneCardInfo, boolean theSame) {
        boolean send = false;
        ISceneCardInfo cardInfo = null;
        //V1
        if (mSceneCallback != null && mSceneCallback.size() > 0) {
            Log.i(TAG, "callback size " + mSceneCallback.size() + ",lastSendSceneInfo " + lastSendSceneInfo);
            cardInfo = new ISceneCardInfo(iSceneCardInfo.getId(), iSceneCardInfo.getPkgname(), iSceneCardInfo.isBeep(), iSceneCardInfo.isTts(),
                    iSceneCardInfo.isSeeSay(), iSceneCardInfo.getTitle(), iSceneCardInfo.getSubtitle(), iSceneCardInfo.getTag(), iSceneCardInfo.getWhen(), iSceneCardInfo.getActions(),
                    iSceneCardInfo.getSeeSayActions(), iSceneCardInfo.getSmartCardActions());
            for (ISceneCardListener listener : mSceneCallback) {
                try {
                    Log.i(TAG, listener + " listener  " + listener.onSceneInfoInShowing() + ", the same " + theSame);
                    if (!listener.onSceneInfoInShowing() || theSame) {
                        listener.onSceneCardPosted(cardInfo);
                        lastSendSceneInfo = iSceneCardInfo;
                        send = true;
                        Log.i(TAG, "scene card send out " + iSceneCardInfo.toString());
                    } else {
                        Log.i(TAG, "scene card can not send out to " + listener);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        //V2
        if (mSceneCallbackV2 != null && mSceneCallbackV2.size() > 0) {
            Log.i(TAG, "callback V2 size " + mSceneCallbackV2.size() + ",lastSendSceneInfo " + lastSendSceneInfo);
            for (ISceneCardListenerV2 listener : mSceneCallbackV2) {
                try {
                    Log.i(TAG, listener + " listener V2 " + listener.onSceneInfoInShowing() + ", the same " + theSame);
                    if (!listener.onSceneInfoInShowing() || theSame) {
                        listener.onSceneCardPosted(iSceneCardInfo);
                        lastSendSceneInfo = iSceneCardInfo;
                        send = true;
                        Log.i(TAG, "v2 scene card send out " + iSceneCardInfo.toString());
                    } else {
                        Log.i(TAG, "v2 scene card can not send out to " + listener);
                    }

                } catch (Exception e) {
                    Log.e(TAG, "v2 client exception");
                }
            }
        }

        if (send) {
            //V1 版本
            if (mSceneCallback != null && mSceneCallback.size() > 0 && cardInfo != null) {
                for (ISceneCardListener listener : mSceneCallback) {
                    try {
                        Log.i(TAG, "send card to scene");
                        listener.onQuickCardPosted(cardInfo);
                    } catch (Exception e) {
                        Log.e(TAG, "send card to scene failure " + e);
                    }
                }
            }

            //V2 版本
            if (mSceneCallbackV2 != null && mSceneCallbackV2.size() > 0) {
                for (ISceneCardListenerV2 listener : mSceneCallbackV2) {
                    try {
                        Log.i(TAG, "send v2 card to scene");
                        listener.onQuickCardPosted(iSceneCardInfo);
                    } catch (Exception e) {
                        Log.e(TAG, "send V2 card to scene failure " + e);
                    }
                }
            }

            mQueueManager.removeSceneCard(iSceneCardInfo);
        }

        return send;
    }

    private boolean onNotificationSend(Competition competition) {
        if (mCallbackList == null || mCallbackList.size() <= 0) {
            Log.w(TAG, "No client receive card notification.");
            return false;
        }

        boolean isSendOut = false;

        for (ICardNotificationListener listener : mCallbackList) {
            try {
                if (listener != null && listener.getPushNotificationWaitingTime() <= 0) {
                    Log.i(TAG, "onNotificationSend " + competition.getNotificationBar().getKey());
                    listener.onNotificationPosted(competition.getNotificationBar());
                    isSendOut = true;
                }
            } catch (Exception e) {
                Log.e(TAG, "client exception " + e);
            }
        }
        if (isSendOut) {
            mPastCompetition = competition;
            mQueueManager.removeCompetitionFromQueue(competition);
            return true;
        } else {
            Log.i(TAG, "all client refused to receive a new card notification, have  add " + competition.getNotificationBar().getKey() + " into queue.");
        }

        return false;

    }

    /**
     * 取消形象卡片提示
     *
     * @param notification {@link IStatusBarNotification}
     * @since 1.0.0
     */
    public void enqueueNotification(IStatusBarNotification notification) {
        if (notification == null) {
            Log.w(TAG, "card tips info is null");
            return;
        }

        final Competition competition = new BuildCompetition().newBuilder(notification).build();
        enqueueCardQueue(competition);
    }

    private void enqueueCardQueue(final Competition competition) {
        boolean isAccessCompetition = false;
        Log.d(TAG, competition.getNotificationBar().toString());
        if (mQueueManager != null && mQueueManager.getCompetition() == null) {
            isAccessCompetition = onNotificationSend(competition);
        }
        if (!isAccessCompetition && mQueueManager != null) {
            Log.i(TAG, "start add card tips notification to queue.");
            TPE.get().submitDefaultOrderedTasks(new Callback<Void>() {
                @Override
                public Void doBackground() throws Exception {
                    mQueueManager.addQueue(competition);
                    return super.doBackground();
                }
            });
        }
    }

    /**
     * 消息发送方主动取消通知
     */
    public void cancelNotification(IStatusBarNotification notification) {
        Competition competition = new BuildCompetition().newBuilder(notification).build();
        if (mCallbackList != null) {
            String key = mQueueManager.getRemovedInfoKey(competition.getNotificationBar().getKey());
            Log.i(TAG, "remove card notification info key " + key);
            if (!TextUtils.isEmpty(key) && mPastCompetition != null) {
                if (mPastCompetition.getNotificationBar().getKey().equals(key)) {
                    key = mPastCompetition.getNotificationBar().getKey();
                    Log.i(TAG, "current card tip notification info key " + key);
                }
                cancel(competition);
            }
        }
    }

    private void cancel(Competition competition) {
        for (ICardNotificationListener listener : mCallbackList) {
            if (listener != null) {
                try {
                    Log.i(TAG, "card notification removed by " + listener);
                    listener.onNotificationRemoved(competition.getNotificationBar());
                } catch (Exception e) {
                    Log.e(TAG, "card notification removed exception " + e);
                }
            }
        }
        if (mQueueManager != null) {
            Log.i(TAG, competition.getNotificationBar().getKey() + "card notification tips removed");
            mQueueManager.removeCompetitionByKey(competition.getNotificationBar().getKey());
        }
    }

    public void setRemoteCallbackList(List<ICardNotificationListener> cardListenerList) {
        this.mCallbackList = cardListenerList;
    }

    public void setRemoteSceneCallbackList(List<ISceneCardListener> list) {
        this.mSceneCallback = list;
    }

    public void setRemoteSceneCallbackListV2(List<ISceneCardListenerV2> list) {
        this.mSceneCallbackV2 = list;
    }

    /**
     * 形象app主动请求告知launcher controller 现在可以接收消息
     */
    public void sendNotification(int status) {
        if (mQueueManager == null || status == Constants.ICardHandleStatus.STATUS_NO_HANDLE) {
            return;
        }
        Competition competition = mQueueManager.getCompetition();
        ISceneCardInfoV2 sceneCard = mQueueManager.getSceneCard();
        if (competition == null) {
            Log.w(TAG, "No card notification, stop.");
            if (sceneCard == null) {
                Log.w(TAG, "No scene card notification, stop.");
            } else {
                doSend(sceneCard, false);
            }
        } else {
            if (sceneCard == null) {
                Log.w(TAG, "No scene card notification");
                onNotificationSend(competition);
            } else {
                if (sceneCard.getWhen() < competition.getNotificationBar().getWhen()) {
                    doSend(sceneCard, false);
                } else {
                    onNotificationSend(competition);
                }
            }
        }
    }

    public void enqueueSceneCard(ISceneCardInfoV2 iSceneCardInfo) {
        Log.i(TAG, "dispatch scene card " + iSceneCardInfo.toString());
        boolean send;
        if (lastSendSceneInfo == null) {
            send = doSend(iSceneCardInfo, false);
        } else {
            if (lastSendSceneInfo.getKey().equals(iSceneCardInfo.getKey())) {
                send = doSend(iSceneCardInfo, true);
            } else {
                send = doSend(iSceneCardInfo, false);
            }
        }

        if (!send) {
            mQueueManager.addSceneCardQueue(iSceneCardInfo);
        }
    }

    public void removeSceneCard(ISceneCardInfoV2 iSceneCardInfo) {
        Log.i(TAG, "scene card removed " + iSceneCardInfo.toString());
        mQueueManager.removeSceneCard(iSceneCardInfo);
        if (lastSendSceneInfo != null && lastSendSceneInfo.getKey().equals(iSceneCardInfo.getKey())) {

            if (mSceneCallback != null && mSceneCallback.size() > 0) {
                ISceneCardInfo cardInfo = new ISceneCardInfo(iSceneCardInfo.getId(), iSceneCardInfo.getPkgname(), iSceneCardInfo.isBeep(), iSceneCardInfo.isTts(),
                        iSceneCardInfo.isSeeSay(), iSceneCardInfo.getTitle(), iSceneCardInfo.getSubtitle(), iSceneCardInfo.getTag(), iSceneCardInfo.getWhen(), iSceneCardInfo.getActions(),
                        iSceneCardInfo.getSeeSayActions(), iSceneCardInfo.getSmartCardActions());
                for (ISceneCardListener listener : mSceneCallback) {
                    try {
                        listener.onSceneCardRemoved(cardInfo);
                        Log.d(TAG, "card removed " + iSceneCardInfo.toString());
                    } catch (Exception e) {
                        Log.e(TAG, "card remove exception " + e);
                    }
                }
            }

            if (mSceneCallbackV2 != null && mSceneCallbackV2.size() > 0) {
                for (ISceneCardListenerV2 listener : mSceneCallbackV2) {
                    try {
                        listener.onSceneCardRemoved(iSceneCardInfo);
                        Log.d(TAG, "card removed " + iSceneCardInfo.toString());
                    } catch (Exception e) {
                        Log.e(TAG, "card remove exception " + e);
                    }
                }
            }
        }

    }

    public void notifySceneCardStatusChange() {
        if (mQueueManager.getSceneCard() == null) {
            lastSendSceneInfo = null;
            Log.i(TAG, "no scene card in the queue");
            return;
        }
        doSend(mQueueManager.getSceneCard(), false);
    }

}
